fix(convert): pad SVS/TIFF edge tiles + synthesize Aperio thumbnail at IFD 1#20
Merged
Merged
Conversation
…t IFD 1 Two Aperio-ecosystem conformance bugs in v0.24.0 SVS/TIFF output that OpenSlide/ImageScope reject but opentile (lenient) masked. 1. Edge-tile padding. The retile engine encoded partial right/bottom edge tiles — and whole levels smaller than one tile — at truncated content size. TIFF requires uniform full TileWidth×TileLength tiles (extra pixels are padding); OpenSlide/ImageScope read a sub-full-size JPEG as a "dimensional mismatch" and render black/garbled edges. codecTileEncoder now edge-replicates partial tiles up to the full tile size before encoding, across every engine-backed re-encode path (convert --to svs|tiff|ome-tiff|cog-wsi, --factor, downsample, crop, --to ife). DZI/SZI use partial edges legitimately via internal/dzi's own encoders and are unaffected. 2. Aperio thumbnail at IFD 1. Genuine Aperio SVS always carries the thumbnail as the second IFD; ImageScope classifies IFD 1 positionally as the thumbnail, so a source without one (BIF, IFE/Iris) left the first reduced level at IFD 1 and ImageScope dropped it. emitSVSThumbnailAtL0 now synthesizes a 1024px baseline- JPEG thumbnail from L0 (via streamCropThumbnail) when the source lacks one, matching the genuine layout. Sources with a thumbnail are unchanged; the associated-image edit rebuilds pass a nil slide (no synthesis, faithful copy). Verified pixel-faithful against OpenSlide on a Ventana BIF→svs (no dimensional mismatch; full slide renders clean) and IFD layout matches genuine Aperio (CMU-1). Tests: padRGBTileReplicate unit; integration TestSVSEdgeTilesAreFullSize (edge tile JPEGs are full tile size) and TestSVSSynthesizesThumbnailAtIFD1 (thumbnail at IFD 1, no level eaten). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Two Aperio-ecosystem conformance bugs in v0.24.0 SVS/TIFF output — OpenSlide/ImageScope reject them; opentile (lenient) masked them.
Bug A — edge-tile corruption (TIFF conformance)
The retile engine encoded partial right/bottom edge tiles, and whole levels smaller than one tile, at truncated content size. TIFF requires uniform full
TileWidth×TileLengthtiles; OpenSlide/ImageScope read a sub-full-size JPEG as a "dimensional mismatch" → black/garbled edges.codecTileEncodernow edge-replicates partial tiles up to full size before encoding, across every engine-backed re-encode path (convert --to svs|tiff|ome-tiff|cog-wsi,--factor,downsample,crop,--to ife). DZI/SZI use partial edges legitimately and are unaffected.Bug B — dropped pyramid level in ImageScope
Genuine Aperio SVS always carries the thumbnail as the second IFD; ImageScope classifies IFD 1 positionally as the thumbnail, so a source without one (BIF, IFE/Iris) left the first reduced level at IFD 1 and ImageScope dropped it (a 1×/4×/16×/64× source showed only 1×/16×/64×).
--to svsnow synthesizes a 1024px Aperio thumbnail from L0 when the source has none.Verification
padRGBTileReplicateunit test + integrationTestSVSEdgeTilesAreFullSizeandTestSVSSynthesizesThumbnailAtIFD1. Full integration + unit suites pass locally.Test Plan
🤖 Generated with Claude Code